<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>Writing Clients</title>
  </head>

  <body>
    <h1>Writing Clients</h1>

    <h2>Overview</h2>

    <p>Twisted is a framework designed to be very flexible, and let you write
    powerful clients. The cost of this flexibility is a few layers in the way
    to writing your client. This document covers creating clients that can be
    used for TCP, SSL and Unix sockets. UDP is covered <a href="udp.xhtml">in
    a different document</a>.</p>

    <p>At the base, the place where you actually implement the protocol parsing
    and handling, is the <code>Protocol</code> class. This class will usually be
    descended
    from <code class="API">twisted.internet.protocol.Protocol</code>. Most
    protocol handlers inherit either from this class or from one of its
    convenience children. An instance of the protocol class will be instantiated
    when you connect to the server and will go away when the connection is
    finished.  This means that persistent configuration is not saved in the
    <code>Protocol</code>.</p>

    <p>The persistent configuration is kept in a <code>Factory</code>
    class, which usually inherits from <code class="API">twisted.internet.protocol.Factory</code>
    (or <code class="API">twisted.internet.protocol.ClientFactory</code>: see
    below). The default factory class just instantiates the <code>Protocol</code>
    and then sets the protocol's <code>factory</code> attribute to point to
    itself (the factory). This lets the <code>Protocol</code> access, and
    possibly modify, the persistent configuration.</p>

    <h2>Protocol</h2>

    <p>As mentioned above, this and auxiliary classes and functions are where
    most of the code is. A Twisted protocol handles data in an asynchronous
    manner. This means that the protocol never waits for an event, but rather
    responds to events as they arrive from the network.</p>

    <p>Here is a simple example:</p>

    <pre class="python">
from twisted.internet.protocol import Protocol
from sys import stdout

class Echo(Protocol):
    def dataReceived(self, data):
        stdout.write(data)
    </pre>

    <p>This is one of the simplest protocols.  It just writes whatever it reads
    from the connection to standard output. There are many events it does not
    respond to. Here is an example of a <code>Protocol</code> responding to
    another event:</p>

    <pre class="python">
from twisted.internet.protocol import Protocol

class WelcomeMessage(Protocol):
    def connectionMade(self):
        self.transport.write("Hello server, I am the client!\r\n")
        self.transport.loseConnection()
    </pre>

    <p>This protocol connects to the server, sends it a welcome message, and
    then terminates the connection.</p>

    <p>The <code class="API"
    base="twisted.internet.protocol.BaseProtocol">connectionMade</code> event is
    usually where set up of the <code>Protocol</code> object happens, as well as
    any initial greetings (as in the
    <code>WelcomeMessage</code> protocol above). Any tearing down of
    <code>Protocol</code>-specific objects is done in <code class="API"
    base="twisted.internet.protocol.Protocol">connectionLost</code>.</p>

    <h2>Simple, single-use clients</h2>

    <p>In many cases, the protocol only needs to connect to the server once, and
    the code just wants to get a connected instance of the protocol. In those
    cases <code class="API">twisted.internet.endpoints</code> provides the
    appropriate API.</p>

    <pre class="python">
from twisted.internet import reactor
from twisted.internet.protocol import Factory, Protocol
from twisted.internet.endpoints import TCP4ClientEndpoint

class Greeter(Protocol):
    def sendMessage(self, msg):
        self.transport.write("MESSAGE %s\n" % msg)

class GreeterFactory(Factory):
    def buildProtocol(self, addr):
        return Greeter()

def gotProtocol(p):
    p.sendMessage("Hello")
    reactor.callLater(1, p.sendMessage, "This is sent in a second")
    reactor.callLater(2, p.transport.loseConnection)

point = TCP4ClientEndpoint(reactor, "localhost", 1234)
d = point.connect(GreeterFactory())
d.addCallback(gotProtocol)
reactor.run()
    </pre>

    <p>Regardless of the type of client endpoint, the way to set up a new
    connection is simply to call the <code>connect</code> method on it and pass
    in a factory.  This means it's easy to change the mechanism you're using to
    connect, without changing the rest of your program.  For example, to run
    the greeter example over SSL, the only change required is to instantiate an
    <code class="API"
    base="twisted.internet.endpoints">SSL4ClientEndpoint</code> instead of a
    <code>TCP4ClientEndpoint</code>.  To take advantage of this, functions and
    methods which initiates a new connection should generally accept an
    endpoint as an argument and let the caller construct it, rather than taking
    arguments like 'host' and 'port' and constructing its own before calling
    <code>connect</code>.</p>

    <p>For more information on different ways you can make outgoing connections
    to different types of endpoints, as well as parsing strings into endpoints,
    see <a href="endpoints.xhtml">the documentation for the endpoints
    API</a>.</p>

    <div class="note">If you've used <code>ClientFactory</code> before,
    make sure you remember that the <code>connect</code> method takes a
    <code>Factory</code>, not a <code>ClientFactory</code>.  Even if you pass a
    <code>ClientFactory</code> to <code>endpoint.connect</code>, its
    <code>clientConnectionFailed</code> and <code>clientConnectionLost</code>
    methods will not be called.</div>

    <p>You may come across code using <code base="twisted.internet.protocol"
    class="API">ClientCreator</code>, an older API which is not as flexible as
    the endpoint API.  Rather than calling <code>connect</code> on an endpoint,
    such code will look like this:</p>

    <pre class="python">
from twisted.internet.protocol import ClientCreator

...

creator = ClientCreator(reactor, Greeter)
d = creator.connectTCP("localhost", 1234)
d.addCallback(gotProtocol)
reactor.run()
    </pre>

    <p>In general, the endpoint API should be preferred in new code, as it lets
    the caller select the method of connecting.</p>

    <h2>ClientFactory</h2>

    <p>Still, there's plenty of code out there that uses lower-level APIs, and
    a few features (such as automatic reconnection) have not been
    re-implemented with endpoints yet, so in some cases they may be more
    convenient to use.</p>

    <p>To use the lower-level connection APIs, you will need to call one of the
    <em>reactor.connect*</em> methods directly.  For these cases, you need a
    <code class="API" base="twisted.internet.protocol">ClientFactory</code>.
    The <code>ClientFactory</code> is in charge of creating the
    <code>Protocol</code> and also receives events relating to the connection
    state. This allows it to do things like reconnect in the event of a
    connection error. Here is an example of a simple <code>ClientFactory</code>
    that uses the <code>Echo</code> protocol (above) and also prints what state
    the connection is in.</p>

    <pre class="python">
from twisted.internet.protocol import Protocol, ClientFactory
from sys import stdout

class Echo(Protocol):
    def dataReceived(self, data):
        stdout.write(data)

class EchoClientFactory(ClientFactory):
    def startedConnecting(self, connector):
        print 'Started to connect.'

    def buildProtocol(self, addr):
        print 'Connected.'
        return Echo()

    def clientConnectionLost(self, connector, reason):
        print 'Lost connection.  Reason:', reason

    def clientConnectionFailed(self, connector, reason):
        print 'Connection failed. Reason:', reason
    </pre>

    <p>To connect this <code>EchoClientFactory</code> to a server, you could use
    this code:</p>

    <pre class="python">
from twisted.internet import reactor
reactor.connectTCP(host, port, EchoClientFactory())
reactor.run()
    </pre>

    <p>Note that <code class="API"
    base="twisted.internet.protocol.ClientFactory">clientConnectionFailed</code>
    is called when a connection could not be established, and that <code
    class="API"
    base="twisted.internet.protocol.ClientFactory">clientConnectionLost</code>
    is called when a connection was made and then disconnected.</p>

    <h3>Reconnection</h3>

    <p>Often, the connection of a client will be lost unintentionally due to
    network problems. One way to reconnect after a disconnection would be to
    call <code>connector.connect()</code> when the connection is lost:</p>

    <pre class="python">
from twisted.internet.protocol import ClientFactory

class EchoClientFactory(ClientFactory):
    def clientConnectionLost(self, connector, reason):
        connector.connect()
    </pre>

    <p>The connector passed as the first argument is the interface between a
    connection and a protocol. When the connection fails and the factory
    receives the <code>clientConnectionLost</code> event, the factory can
    call <code>connector.connect()</code> to start the connection over again
    from scratch.</p>

    <p>
    However, most programs that want this functionality should
    implement <code class="API"
    base="twisted.internet.protocol">ReconnectingClientFactory</code> instead,
    which tries to reconnect if a connection is lost or fails and which
    exponentially delays repeated reconnect attempts.
    </p>

    <p>
    Here is the <code>Echo</code> protocol implemented with
    a <code>ReconnectingClientFactory</code>:
    </p>

    <pre class="python">
from twisted.internet.protocol import Protocol, ReconnectingClientFactory
from sys import stdout

class Echo(Protocol):
    def dataReceived(self, data):
        stdout.write(data)

class EchoClientFactory(ReconnectingClientFactory):
    def startedConnecting(self, connector):
        print 'Started to connect.'

    def buildProtocol(self, addr):
        print 'Connected.'
        print 'Resetting reconnection delay'
        self.resetDelay()
        return Echo()

    def clientConnectionLost(self, connector, reason):
        print 'Lost connection.  Reason:', reason
        ReconnectingClientFactory.clientConnectionLost(self, connector, reason)

    def clientConnectionFailed(self, connector, reason):
        print 'Connection failed. Reason:', reason
        ReconnectingClientFactory.clientConnectionFailed(self, connector,
                                                         reason)
</pre>

    <h2>A Higher-Level Example: ircLogBot</h2>

    <h3>Overview of ircLogBot</h3>

    <p>The clients so far have been fairly simple.  A more complicated example
    comes with Twisted Words in the <code>doc/words/examples</code>
    directory.</p>

    <a href="../../words/examples/ircLogBot.py" class="py-listing"
    skipLines="24">ircLogBot.py</a>

    <p><code>ircLogBot.py</code> connects to an IRC server, joins a channel, and
    logs all traffic on it to a file. It demonstrates some of the
    connection-level logic of reconnecting on a lost connection, as well as
    storing persistent data in the <code>Factory</code>.</p>

    <h3>Persistent Data in the Factory</h3>

    <p>Since the <code>Protocol</code> instance is recreated each time the
    connection is made, the client needs some way to keep track of data that
    should be persisted. In the case of the logging bot, it needs to know which
    channel it is logging, and where to log it.</p>

    <pre class="python">
from twisted.words.protocols import irc
from twisted.internet import protocol

class LogBot(irc.IRCClient):

    def connectionMade(self):
        irc.IRCClient.connectionMade(self)
        self.logger = MessageLogger(open(self.factory.filename, "a"))
        self.logger.log("[connected at %s]" %
                        time.asctime(time.localtime(time.time())))

    def signedOn(self):
        self.join(self.factory.channel)


class LogBotFactory(protocol.ClientFactory):

    def __init__(self, channel, filename):
        self.channel = channel
        self.filename = filename

    def buildProtocol(self, addr):
        p = LogBot()
        p.factory = self
        return p
    </pre>

    <p>When the protocol is created, it gets a reference to the factory as
    <code>self.factory</code>. It can then access attributes of the factory in
    its logic. In the case of <code>LogBot</code>, it opens the file and
    connects to the channel stored in the factory.</p>

    <p>Factories have a default implementation of <code>buildProtocol</code>
    that does the same thing the example above does, using
    the <code>protocol</code> attribute of the factory to create the protocol
    instance. In the example above, the factory could be rewritten to look
    like this:</p>

    <pre class="python">
class LogBotFactory(protocol.ClientFactory):
    protocol = LogBot

    def __init__(self, channel, filename):
        self.channel = channel
        self.filename = filename
    </pre>

    <h2>Further Reading</h2>

    <p>The <code class="API" base="twisted.internet.protocol">Protocol</code>
    class used throughout this document is a base implementation
    of <code class="API" base="twisted.internet.interfaces">IProtocol</code>
    used in most Twisted applications for convenience. To learn about the
    complete <code>IProtocol</code> interface, see the API documentation for
    <code class="API" base="twisted.internet.interfaces">IProtocol</code>.</p>

    <p>The <code>transport</code> attribute used in some examples in this
    document provides the <code class="API"
    base="twisted.internet.interfaces">ITCPTransport</code> interface. To learn
    about the complete interface, see the API documentation
    for <code class="API"
    base="twisted.internet.interfaces">ITCPTransport</code>.</p>

    <p>Interface classes are a way of specifying what methods and attributes an
    object has and how they behave. See the <a href="components.xhtml">
    Components: Interfaces and Adapters</a> document for more information on
    using interfaces in Twisted.</p>
  </body>
</html>
